package com.xored.glance.ui.controls.decor;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.TextLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Listener;

public class StructDecorator implements Listener {

	public static final int ERASE_STYLE = SWT.BACKGROUND | SWT.FOREGROUND
			| SWT.SELECTED | SWT.HOT;

	private Composite composite;
	private IStructProvider provider;

	private TextLayout textLayout;

	public StructDecorator(Composite composite, IStructProvider provider) {
		this.composite = composite;
		this.provider = provider;
		init();
	}

	public void redraw() {
		Rectangle rect = composite.getClientArea();
		composite.redraw(rect.x, rect.y, rect.width, rect.height, true);
	}

	public void redraw(StructCell cell) {
		Rectangle rect = cell.getBounds();
		composite.redraw(rect.x, rect.y, rect.width, rect.height, true);
	}

	protected TextLayout getTextLayout() {
		if (textLayout == null) {
			int orientation = composite.getStyle()
					& (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
			textLayout = new TextLayout(composite.getDisplay());
			textLayout.setOrientation(orientation);
		} else {
			textLayout.setText("");
		}
		return textLayout;
	}

	public void handleEvent(Event event) {
		switch (event.type) {
		case SWT.PaintItem:
			paint(event);
			break;
		case SWT.EraseItem:
			erase(event);
			break;
		}
	}

	protected void paint(Event event) {
		Item item = (Item) event.item;
		GC gc = event.gc;
		// remember colors to restore the GC later
		Color oldForeground = gc.getForeground();
		Color oldBackground = gc.getBackground();

		StructCell cell = provider.getCell(item, event.index);

		Color foreground = cell.getForeground();
		if (foreground != null) {
			gc.setForeground(foreground);
		}

		Color background = cell.getBackground();
		if (background != null) {
			gc.setBackground(background);
		}

		if ((event.detail & SWT.SELECTED) != 0) {
			Color color = new Color(null, 232, 242, 254);
			gc.setBackground(color);
		}

		gc.fillRectangle(cell.getBounds());

		Image image = cell.getImage();
		if (image != null) {
			Rectangle imageBounds = cell.getImageBounds();
			if (imageBounds != null) {
				Rectangle bounds = image.getBounds();

				// center the image in the given space
				int x = imageBounds.x
						+ Math.max(0, (imageBounds.width - bounds.width) / 2);
				int y = imageBounds.y
						+ Math.max(0, (imageBounds.height - bounds.height) / 2);
				gc.drawImage(image, x, y);
			}
		}

		Rectangle textBounds = cell.getTextBounds();
		if (textBounds != null) {
			TextLayout layout = getTextLayout();
			layout.setText(cell.getText());
			layout.setFont(cell.getFont());

			StyleRange[] styles = cell.styles;
			for (StyleRange range : styles) {
				layout.setStyle(range, range.start, range.start + range.length
						- 1);
			}

			Rectangle layoutBounds = layout.getBounds();

			int x = textBounds.x;
			int avg = (textBounds.height - layoutBounds.height) / 2;
			int y = textBounds.y + Math.max(0, avg);

			layout.draw(gc, x, y);
		}

		gc.setForeground(oldForeground);
		gc.setBackground(oldBackground);
	}

	public void erase(Event event) {
		event.detail &= ~ERASE_STYLE;
	}

	protected void init() {
		composite.addListener(SWT.EraseItem, this);
		composite.addListener(SWT.PaintItem, this);
		redraw();
	}

	public void dispose() {
		if (!disposed) {
			disposed = true;
			if (!composite.isDisposed()) {
				composite.removeListener(SWT.PaintItem, this);
				composite.removeListener(SWT.EraseItem, this);
				redraw();
			}
		}
	}

	public boolean isDisposed() {
		return disposed;
	}

	private boolean disposed;

}
